﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sustainalytics.ScreeningTool.BL;
using Sustainalytics.DataLayer;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Sustainalytics.Entities;
using Sustainalytics.ScreeningTool.BL.Model;
using Moq;
using Sustainalytics.Claims;
using System.Security.Claims;
using Newtonsoft.Json;
using System.Security.Principal;

namespace Sustainalytics.ScreeningTool.Service.Tests
{

    [TestClass()]
    public class FiltersControllerTests
    {

        private List<Filter> mockFilters = new List<Filter>()
        {
            new Filter() { 
                Id = new Guid("6908FFCF-0530-4115-91C4-52D01CF2E48C"),
                Name="my custom filter 1",
                Type=FilterType.Private,
                OwnerUserId = new Guid("11111111-1111-0000-0000-000000000000"),
                AccountId = new Guid("11111111-0000-0000-0000-000000000000"),
                IsFavorite= false,
                Status = FilterStatus.Active,
                TargetType= TargetType.Screening
            },

            new Filter() { 
                Id = new Guid("8B076072-9A18-4728-80E9-4B9236D19E91"),
                Name="my custom filter 2 fav",
                Type=FilterType.Private,
                OwnerUserId = new Guid("11111111-1111-0000-0000-000000000000"),
                AccountId = new Guid("11111111-0000-0000-0000-000000000000"),
                IsFavorite= true,
                Status = FilterStatus.Active,
                TargetType= TargetType.Screening
            },

            new Filter() { 
                Id = new Guid("C7E964A0-9246-46C4-B895-19C9221C211A"),
                Name="shared from account not owned by current user",
                Type=FilterType.Shared,
                OwnerUserId = new Guid("4C9AF559-5D2F-4A6C-AD90-DEC585D002C4"),
                AccountId = new Guid("11111111-0000-0000-0000-000000000000"),
                IsFavorite= true,
                Status = FilterStatus.Active,
                TargetType= TargetType.Screening
            },

            new Filter() { 
                Id = new Guid("86D0B8C9-136B-4B9A-B761-D02E0D3F599E"),
                Name="shared from account not owned by current user",
                Type=FilterType.Standard,
                OwnerUserId = new Guid("38DA5AC4-1705-4229-8099-C239A9EA05C2"),
                AccountId = new Guid("11111111-0000-0000-0000-000000000000"),
                IsFavorite= false,
                Status = FilterStatus.Active,
                TargetType= TargetType.Screening
            }
        };

        private User mockCurrentUser = new User() { 
            Id = new Guid("11111111-1111-0000-0000-000000000000"), 
            AccountId = new Guid("11111111-0000-0000-0000-000000000000"), 
            Email = "testuser@sustainalytics.com" 
        };


        [TestMethod]
        public void GetReturnsExpectedFilters()
        {
            // Arrange

            var filterOptions = new FilterOptions() { WithExtendedData = false, Target = TargetType.Screening };

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.GetUserFilters(It.IsAny<string>(), It.IsAny<TargetType>()))
                .Returns(mockFilters);

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            mockIAccountsRepository.Setup(x => x.GetUserByUserId(It.IsAny<Guid>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Get(filterOptions);

            //Assert
            string jsonString = response.Content.ReadAsStringAsync().Result;
            List<FilterDto> actualResult = JsonConvert.DeserializeObject<List<FilterDto>>(jsonString);

            Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);
            Assert.AreEqual(mockFilters.Count, actualResult.Count);

        }


        [TestMethod]
        public void GetWithUnknownUserReturnsUnknownUserException()
        {

            // Arrange
            var filterOptions = new FilterOptions() { WithExtendedData = false, Target = TargetType.Screening };

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.GetUserFilters(It.IsAny<string>(), It.IsAny<TargetType>()))
                .Returns(mockFilters);

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(()=>{ return null; });


            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());
            controller.User = new GenericPrincipal(new GenericIdentity("testuser@sustainalytics.com"), new[] { "" });

            // Act
            var response = controller.Get(filterOptions);

            //Assert
            string jsonString = response.Content.ReadAsStringAsync().Result;
            Assert.IsTrue(response.StatusCode == HttpStatusCode.Unauthorized);

        }

        [TestMethod]
        public void GetWithNoClaimsOnFiltersReturnsAuthorizationException()
        {
            // Arrange
            var filterOptions = new FilterOptions() { WithExtendedData = false, Target = TargetType.Screening };

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.GetUserFilters(It.IsAny<string>(), It.IsAny<TargetType>()))
                .Returns(mockFilters);

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(false);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            mockIAccountsRepository.Setup(x => x.GetUserByUserId(It.IsAny<Guid>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Get(filterOptions);

            //Assert
            string jsonString = response.Content.ReadAsStringAsync().Result;
            Assert.IsTrue(response.StatusCode == HttpStatusCode.Unauthorized);
        }
        //

        [TestMethod]
        public void GetFilterReturnsExpectedFilter()
        {
            // Arrange
            var filterId = new Guid("6908FFCF-0530-4115-91C4-52D01CF2E48C");
            var foundFilter = mockFilters.Find(x => x.Id == filterId);

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.LoadFilter(filterId, It.IsAny<string>() ))
                .Returns(foundFilter);

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Get(filterId, mockCurrentUser.AccountId.Value, mockCurrentUser.Id, false);

            //Assert
            string jsonString = response.Content.ReadAsStringAsync().Result;
            FilterDto actualResult = JsonConvert.DeserializeObject<FilterDto>(jsonString);

            Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);
            Assert.AreEqual(foundFilter.Id, actualResult.Id);
        }
        //

        [TestMethod]
        public void PostFilterReturnsFilterAndOkStatusCode()
        {

            var postedObject = new FilterAddEditDto()
            {
                Name="new custom filter",
                Type = FilterType.Private,
                OwnerUserId = mockCurrentUser.Id,
                AccountId = mockCurrentUser.AccountId.Value,
                CreatedAt = DateTime.Now,
                IsFavorite = false,
                Status = FilterStatus.Active,
                TargetType = TargetType.Screening
            };

            Guid generatedId = Guid.NewGuid();
            var expectedResult = new Filter()
            {
                Id = generatedId,
                Name = postedObject.Name,
                Type= postedObject.Type,
                OwnerUserId = postedObject.OwnerUserId,
                AccountId = postedObject.AccountId,
                CreatedAt = postedObject.CreatedAt,
                IsFavorite = postedObject.IsFavorite,
                Status = postedObject.Status,
                TargetType = postedObject.TargetType,
                ExportType =  ExportType.Excel
            };

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.SaveFilter(It.IsAny<string>(), postedObject))
                .Returns(expectedResult);

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Post(postedObject);

            //Assert
            string jsonString = response.Content.ReadAsStringAsync().Result;
            Filter actualResult = JsonConvert.DeserializeObject<Filter>(jsonString);

            Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);

        }
        //

        [TestMethod]
        public void PutFilterReturnsOkStatusCode()
        {
            var postedObject = new FilterDto()
            {
                Id = new Guid("C7E964A0-9246-46C4-B895-19C9221C211A"),
                Name = "new custom filter edited (shared and fav)",
                Type = FilterType.Shared,
                OwnerUserId = mockCurrentUser.Id,
                AccountId = mockCurrentUser.AccountId.Value,
                CreatedAt = DateTime.Now,
                IsFavorite = true,
                Status = FilterStatus.Active,
                TargetType = TargetType.Screening
            };

            var postedObjectToFilter = new Filter() {
                Id = new Guid("C7E964A0-9246-46C4-B895-19C9221C211A"),
                Name = "new custom filter edited (shared and fav)",
                Type = FilterType.Shared,
                OwnerUserId = mockCurrentUser.Id,
                AccountId = mockCurrentUser.AccountId.Value,
                CreatedAt = DateTime.Now,
                IsFavorite = true,
                Status = FilterStatus.Active,
                TargetType = TargetType.Screening
            };


            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.EditFilter(It.IsAny<string>(), postedObjectToFilter));

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Put(postedObject);

            //Assert
            Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);
        }
        //

        [TestMethod]
        public void DeleteFilterReturnsNoContent()
        {

            var filterId = new Guid("6908FFCF-0530-4115-91C4-52D01CF2E48C");

            var mockIFilterManager = new Mock<IFilterManager>();
            mockIFilterManager.Setup(x => x.DeleteFullFilter(filterId, mockCurrentUser.Email));
           

            var mockIClaimsChecker = new Mock<IClaimsChecker>();
            mockIClaimsChecker.Setup(x => x.Validate(It.IsAny<ClaimsPrincipal>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<List<ResourceParameters>>()))
                .Returns(true);

            var mockIAccountsRepository = new Mock<IAccountsRepository>();
            mockIAccountsRepository.Setup(x => x.GetUserByUsername(It.IsAny<string>()))
                .Returns(mockCurrentUser);

            var controller = new FiltersController(mockIFilterManager.Object, mockIClaimsChecker.Object, mockIAccountsRepository.Object);

            controller.Request = new HttpRequestMessage();
            controller.Request.SetConfiguration(new HttpConfiguration());

            // Act
            var response = controller.Delete(filterId);

            //Assert
            Assert.IsTrue(response.StatusCode == HttpStatusCode.NoContent);
        }
        //

    }
   
}
